package reflection;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String str1 = "abc";
        //3种获取方式
        Class cls1 = str1.getClass();
        Class cls2 = String.class;
        Class cls3 = Class.forName("java.lang.String");

        //三个引用对象指向同一份字节码(String)的字节码
        //一个类一份字节码,一份字节码可以搞出多个实例对象
        System.out.println(cls1 == cls2);
        System.out.println(cls1 == cls3);
        System.out.println(cls1.isPrimitive());
        System.out.println(int.class.isPrimitive());
        System.out.println(int.class == Integer.class);
        System.out.println(int.class == Integer.TYPE);
        System.out.println(int[].class.isPrimitive());
        System.out.println(int[].class.isArray());

        ReflectPoint pt1 = new ReflectPoint(3, 5);
        ReflectPoint pt2 = new ReflectPoint(4, 7);
        //获取y的值,y本身没有值,有的只是pt对象传过去的所以pt1和pt2的y位置的值不一样
        Field fieldY = pt1.getClass().getField("y");
        //fieldY的值是多少?
        //fieldY不是对象身上的变量,而是类上,要用它去取某个对象对应的值
        System.out.println(fieldY.get(pt1));
        System.out.println(fieldY.get(pt2));

        System.out.println("------------------------");
       /* //因为x属性是私有的所以使用getField会报NoSuchFieldException
        Field fieldX = pt1.getClass().getField("x");*/
        /**
         * field代表某一字节码身上的变量,不代表,某一对象身上的变量
         */
        Field fieldX = pt1.getClass().getDeclaredField("x");
        //直接取不让,需要加上暴力反射
        fieldX.setAccessible(true);
        System.out.println(fieldX.get(pt1));
        changeStringValue(pt1);
        System.out.println(pt1);

        System.out.println("===========================");
        //str1.charAt(1)
        Method charAt = String.class.getMethod("charAt", int.class);
        //取str1下标为1的参数
        //invoke调用方法对象身上的方法
        System.out.println(charAt.invoke(str1, 1));

        System.out.println("-------------------------");
        /* String startingClassName = args[0];*/
        //Method mainMethod = Class.forName(startingClassName).getMethod("main", String);

        //数组的后面指定了元素,[]里面就不能再指定个数
        int[] a1 = new int[]{1, 2, 3};
        int[] a2 = new int[4];
        int[][] a3 = new int[4][6];
        String[] a4 = new String[]{"a", "b", "c"};
        //比较对象的字节码需要使用getClass()方法
        //如果类型和维度相同得到的字节码是同一份
        System.out.println(a1.getClass() == a2.getClass());
        //System.out.println(a4.getClass() == a1.getClass());
        //System.out.println(a1.getClass() ==a3.getClass());
        System.out.println(a1.getClass().getName());
        System.out.println(a1.getClass().getSuperclass());
        System.out.println(a4.getClass().getSuperclass());
        Object obj = null;
        //给的是数组就把数组拆开来一个一个打印
        printObject(a4);
        //不是数据就全部打印
        printObject("xyz");

    }

    private static void printObject(Object obj) {
        Class clazz = obj.getClass();
        if (clazz.isArray()) {
            int len = Array.getLength(obj);
            for (int i = 0; i < len; i++) {
                System.out.println(Array.get(obj,i));
            }
        } else {
            System.out.println(obj);
        }
    }

    private static void changeStringValue(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getFields();
        for (Field f : fields) {
            //比较字节码使用 == ,因为是同一份字节码
            if (f.getType() == String.class) {
                String oldValue = (String) f.get(obj);
                String newValue = oldValue.replace("b", "a");
                f.set(obj, newValue);
            }
        }
    }
}

class TestArguments {
    public static void main(String[] args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}
